/* HTTP GET Example using plain POSIX sockets

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/
#include <string.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "protocol_examples_common.h"

#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include "lwip/netdb.h"
#include "lwip/dns.h"

#include "cJSON.h"
#include "cJSON_Utils.h"


#include "app_gui.h"

/* Constants that aren't configurable in menuconfig */
#define WEB_SERVER "www.weather.com.cn"
#define WEB_PORT "80"
#define WEB_PATH "/data/sk/101280101.html"


static const int CONNECTED_BIT = BIT0;

static const char *TAG = "http_request";

static const char *REQUEST = "GET " WEB_PATH " HTTP/1.0\r\n"
    "Host: "WEB_SERVER":"WEB_PORT"\r\n"
    "User-Agent: esp-idf/1.0 esp32\r\n"
    "\r\n";


static EventGroupHandle_t wifi_event_group;   //wifi链接成功事件
static void http_get_task(void *pvParameters);       // HTTP 请求任务

// wifi事件处理
static esp_err_t wifi_event_handler(void *ctx, system_event_t *event)
{
	switch (event->event_id) {
		case SYSTEM_EVENT_STA_START:
			esp_wifi_connect();
			break;
		case SYSTEM_EVENT_STA_GOT_IP:
			xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);
			//xTaskCreate(http_get_task, "http_get_task", 4096, NULL, 3, NULL);

			break;
		case SYSTEM_EVENT_STA_DISCONNECTED:
			esp_wifi_connect();
			xEventGroupClearBits(wifi_event_group, CONNECTED_BIT);
			break;
		default:
			break;
	}
	return ESP_OK;
}

// 解析json数据 只处理 解析 城市 天气 天气代码  温度  其他的自行扩展
static void cjson_to_struct_info(char *text)
{
	cJSON *root,*psub;
	cJSON *Item;

	//截取有效json
	char *index=strchr(text,'{');
	strcpy(text,index);
	root = cJSON_Parse(text);

	if(root!=NULL)
    {
		psub = cJSON_GetObjectItem(root, "weatherinfo");

		if(psub!=NULL){
			Item=cJSON_GetObjectItem(psub,"cityid");
			if(Item!=NULL){
				ESP_LOGI(TAG,"cityid:%s\n",Item->valuestring);
			}

			Item=cJSON_GetObjectItem(psub,"city");
			if(Item!=NULL){
				ESP_LOGI(TAG,"城市:%s\n",Item->valuestring);
			}

			Item=cJSON_GetObjectItem(psub,"WD");
			if(Item!=NULL){
				ESP_LOGI(TAG,"风向:%s\n",Item->valuestring);
			}

			Item=cJSON_GetObjectItem(psub,"temp");
			if(Item!=NULL){
				ESP_LOGI(TAG,"温度:%s\n",Item->valuestring);
			}

			Item=cJSON_GetObjectItem(psub,"SD");
			if(Item!=NULL){
				ESP_LOGI(TAG,"湿度:%s\n",Item->valuestring);
			}

			Item=cJSON_GetObjectItem(psub,"AP");
			if(Item!=NULL){
				ESP_LOGI(TAG,"气压:%s\n",Item->valuestring);
			}

			Item=cJSON_GetObjectItem(psub,"time");
			if(Item!=NULL){
				ESP_LOGI(TAG,"时间:%s\n",Item->valuestring);
			}
		}
	}
	cJSON_Delete(root);
}

static void http_get_task(void *pvParameters)
{
    const struct addrinfo hints = {
        .ai_family = AF_INET,
        .ai_socktype = SOCK_STREAM,
    };
    struct addrinfo *res;
    struct in_addr *addr;
    int s, r;
    char recv_buf[1024];
    char mid_buf[1024];
	int index;

    while(1) 
    {
        int err = getaddrinfo(WEB_SERVER, WEB_PORT, &hints, &res);   //DNS域名解析

        if(err != 0 || res == NULL) {
            ESP_LOGE(TAG, "DNS lookup failed err=%d res=%p", err, res);
            vTaskDelay(1000 / portTICK_PERIOD_MS);
            continue;
        }
       
        addr = &((struct sockaddr_in *)res->ai_addr)->sin_addr;   //打印获取到的IP地址
        ESP_LOGI(TAG, "DNS lookup succeeded. IP=%s", inet_ntoa(*addr));

        s = socket(res->ai_family, res->ai_socktype, 0);    //新创建一个socket
        if(s < 0) {
            ESP_LOGE(TAG, "... Failed to allocate socket.");
            freeaddrinfo(res);
            vTaskDelay(1000 / portTICK_PERIOD_MS);
            continue;
        }
        ESP_LOGI(TAG, "... allocated socket");

        if(connect(s, res->ai_addr, res->ai_addrlen) != 0)   //连接指定的服务器
        {
            ESP_LOGE(TAG, "... socket connect failed errno=%d", errno);
            close(s);
            freeaddrinfo(res);
            vTaskDelay(4000 / portTICK_PERIOD_MS);
            continue;
        }

        ESP_LOGI(TAG, "... connected");
        freeaddrinfo(res);

        if (write(s, REQUEST, strlen(REQUEST)) < 0)    //发送http请求包
        {
            ESP_LOGE(TAG, "... socket send failed");
            close(s);
            vTaskDelay(4000 / portTICK_PERIOD_MS);
            continue;
        }
        ESP_LOGI(TAG, "... socket send success");

        //设置SOCKET接收超时
        struct timeval receiving_timeout;
        receiving_timeout.tv_sec = 5;
        receiving_timeout.tv_usec = 0;
        if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &receiving_timeout,sizeof(receiving_timeout)) < 0) 
        {
            ESP_LOGE(TAG, "... failed to set socket receiving timeout");
            close(s);
            vTaskDelay(4000 / portTICK_PERIOD_MS);
            continue;
        }
        ESP_LOGI(TAG, "... set socket receiving timeout success");

		memset(mid_buf,0,sizeof(mid_buf));   //清空缓存空间

        /* Read HTTP response */
        do {
            bzero(recv_buf, sizeof(recv_buf));
            r = read(s, recv_buf, sizeof(recv_buf)-1);
            strcat(mid_buf,recv_buf);     //把接收到的数据复制出来           
        } while(r > 0);

        ESP_LOGE(TAG, "Rev:%s\n",mid_buf);

        //json解析
		cjson_to_struct_info(mid_buf);
		
        close(s);  //关闭socket，http是短连接

        for(int countdown = 10; countdown >= 0; countdown--) 
        {
            vTaskDelay(1000 / portTICK_PERIOD_MS);
        }
        ESP_LOGI(TAG, "Starting again!");
    }
}

static void show_lcd_gui(void *pvParameters)
{
    lcd_device_init();
    gui_show_bar();

    while (1) 
    {
		vTaskDelay(1000 / portTICK_PERIOD_MS);
	}
}

void app_main(void)
{
    ESP_ERROR_CHECK( nvs_flash_init() );
    ESP_ERROR_CHECK(esp_netif_init());

    //ESP_ERROR_CHECK(esp_event_loop_create_default());

    wifi_event_group = xEventGroupCreate();
	ESP_ERROR_CHECK(esp_event_loop_init(wifi_event_handler, NULL));

    /* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
     * Read "Establishing Wi-Fi or Ethernet Connection" section in
     * examples/protocols/README.md for more information about this function.
     */
    ESP_ERROR_CHECK(example_connect());

    //xTaskCreate(&http_get_task, "http_get_task", 4096, NULL, 5, NULL);
    xTaskCreate(&show_lcd_gui, "show_lcd_gui", 4096, NULL, 5, NULL);

    while (1) 
    {
		vTaskDelay(1000 / portTICK_PERIOD_MS);
	}
    
}
